package com.example.mytestdemo.custom

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Matrix
import android.graphics.RectF
import android.util.Log
import android.util.Size
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.AspectRatio
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.DisplayOrientedMeteringPointFactory
import androidx.camera.core.FocusMeteringAction
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageProxy
import androidx.camera.core.MeteringPoint
import androidx.camera.core.Preview
import androidx.camera.core.TorchState
import androidx.camera.extensions.ExtensionMode
import androidx.camera.extensions.ExtensionsManager
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.heritcoin.coin.lib.util.bitmap.BitmapUtils
import java.io.File
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

/**
 * created tsts
 * 2023/9/11
 */
class CameraXAnalysis(
        private val context: Context,
        private val lifecycleOwner: LifecycleOwner,
        private val previewView: PreviewView,
        private val imageAnalyzerFailCallback: () -> Unit,
        private val imageAnalyzerCallback: (width: Float, height: Float, topMargin: Float, leftMargin: Float,
                                            isBlur: Boolean, luminanceValue: Double?) -> Unit
) {
    private var autoFocusHelper: AutoFocusHelper? = null
    private val TAG = "CameraX"
    private var camera: Camera? = null
    private var imageCapture: ImageCapture? = null//处理闪光灯、拍摄照片
    private var imageAnalyzer: ImageAnalysis? = null//处理图片实时分析

    private var zoomCoefficient: Float = 0.1f//缩放系数
    private var magnificationRate = 2.4f//基准放大倍率, 根据相机的缩放比例，再进行计算

    //记录转换后的真实图片尺寸数据
    private val realImageSize by lazy {
        BitmapUtils.getRealImageSize(previewView)
    }

    /**
     * 图片分析 setAnalyzer 生成的图片旋转角度
     */
    private var imageRotationDegrees = 0
    private var bitmapBuffer: Bitmap? = null//处理图片采集的图片缓存
    private var previewBitmap: Bitmap? = null //相机预览的bitmap

    /** 图片采集线程 */
    private var cameraExecutor: ExecutorService? = null

    //清晰度分析
//    private val blurDetectionHelper by lazy {
//        BlurDetectionHelper(context)
//    }



    init {
        //等待视图正确布局
        previewView.post {
            //设置相机及其用例
            setUpCamera()
        }

        (context as? AppCompatActivity)?.lifecycle?.addObserver(object : LifecycleEventObserver {
            private var currentZoomValue = -1f
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                when (event) {
                    Lifecycle.Event.ON_RESUME -> {
                        setImageAnalysis()
                        if (currentZoomValue != -1f) {
                            camera?.cameraControl?.setZoomRatio(currentZoomValue) //还原缩放值
                        }
                        autoFocusHelper?.autoFocusTimer()
                    }

                    Lifecycle.Event.ON_PAUSE -> {
                        currentZoomValue = camera?.cameraInfo?.zoomState?.value?.zoomRatio ?: -1f
                        imageAnalyzer?.clearAnalyzer()//移除已注册的分析器
                        autoFocusHelper?.autoFocusCancel()
                    }

                    Lifecycle.Event.ON_DESTROY -> {
                        autoFocusHelper?.autoFocusCancel()
                        kotlin.runCatching {
                            cameraExecutor?.shutdown()
                            cameraExecutor?.awaitTermination(1000, TimeUnit.MILLISECONDS);
                        }
                        //blurDetectionHelper.onDestroy()
                    }

                    else -> {}
                }
            }
        })
    }

    /**
     * 拍照
     */
    fun takePicture(saveFile: File, callback: ImageCapture.OnImageSavedCallback) {
        val capture = imageCapture ?: return
        capture.targetRotation = previewView.display.rotation
        val outputOptions = ImageCapture.OutputFileOptions.Builder(saveFile).build()
        capture.takePicture(outputOptions, ContextCompat.getMainExecutor(context), callback)
    }


    // Initialize CameraX, and prepare to bind the camera use cases
    private fun setUpCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
        cameraProviderFuture.addListener({
            // CameraProvider
            val cameraProvider = cameraProviderFuture.get()
            val hasBackCamera = cameraProvider?.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA)

            // Build and bind the camera use cases
            bindCameraUseCases(cameraProvider)

            //设置初始放大
            initZoom()

            //checkForHdrExtensionAvailability(cameraProvider)
        }, ContextCompat.getMainExecutor(context))
    }

    //扩展检测
    private fun checkForHdrExtensionAvailability(cameraProvider: ProcessCameraProvider) {
        val lensFacing = CameraSelector.DEFAULT_BACK_CAMERA

        val availableCameraInfos = cameraProvider?.availableCameraInfos
        Log.e("tag", "摄像头个数 = ${availableCameraInfos?.size}")

        val extensionsManagerFuture = ExtensionsManager.getInstanceAsync(context, cameraProvider)
        extensionsManagerFuture.addListener(
                {
                    val extensionsManager = extensionsManagerFuture.get() ?: return@addListener
                    val isAvailable = extensionsManager.isExtensionAvailable(lensFacing, ExtensionMode.HDR)

                    /**
                     * 检查是否有任何扩展可用性
                     * BOKEH (焦外成像)：在人像模式下拍摄照片时，让前景人物更清晰。
                     * HDR (高动态范围)：拍照时使用不同的自动曝光 (AE) 配置，以获得最佳效果。
                     * NIGHT (夜间)：在低照度环境下 (通常是在夜间) 捕获最佳静态图像。
                     * FACE RETOUCH (脸部照片修复)：拍摄静态图像时，修饰脸部肤色、轮廓等。
                     * AUTO (自动)：根据周围的景色自动调整最终图像。
                     */
                    println("AUTO " + extensionsManager.isExtensionAvailable(lensFacing, ExtensionMode.AUTO))
                    println("HDR " + extensionsManager.isExtensionAvailable(lensFacing, ExtensionMode.HDR))
                    println("FACE RETOUCH " + extensionsManager.isExtensionAvailable(lensFacing, ExtensionMode.FACE_RETOUCH))
                    println("BOKEH " + extensionsManager.isExtensionAvailable(lensFacing, ExtensionMode.BOKEH))
                    println("NIGHT " + extensionsManager.isExtensionAvailable(lensFacing, ExtensionMode.NIGHT))
                    println("NONE " + extensionsManager.isExtensionAvailable(lensFacing, ExtensionMode.NONE))
                },
                ContextCompat.getMainExecutor(context)
        )
    }

    private fun initAutoFocus() {
//        autoFocusHelper = AutoFocusHelper(lifecycleOwner, camera?.cameraControl, cameraPreviewView)
//        autoFocusHelper?.autoFocusTimer()
    }

    // 声明和绑定预览、捕获和分析用例
    private fun bindCameraUseCases(cameraProvider: ProcessCameraProvider) {
        try {
            //CameraSelector-假设我们只使用后置摄像头
            val cameraSelector = CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK).build()

            println("旋转角度 = ${previewView.display.rotation} 预览比例 = ${previewView.width} ,${previewView.height}")

            val preview = Preview.Builder()
                .setTargetAspectRatio(AspectRatio.RATIO_4_3)
                .setTargetRotation(previewView.display.rotation)
                .build()

            imageCapture = ImageCapture.Builder()
                //.setTargetAspectRatio(AspectRatio.RATIO_4_3)//vivo x21输出 5632 : 4224   拍摄时间1.178秒, 1080 * 2, 1440 * 2  0.843秒 4:3的比例输出
                .setTargetResolution(Size(1080 * 2, 1440 * 2)) // 4:3 的比例输出 3840 : 2160 拍摄时间0.7秒
                .setTargetRotation(previewView.display.rotation)//这里拿到的一直是0，实际输出图片旋转了90度
                //.setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) //速度慢，但是质量高
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)//拍照速度快
                .setJpegQuality(100)
                .build()

            // 图像分析
            imageAnalyzer =
                ImageAnalysis.Builder()
                    .setTargetAspectRatio(AspectRatio.RATIO_4_3)
                    .setTargetRotation(previewView.display.rotation)
                    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                    .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
                    .build()
            setImageAnalysis()

            // 必须先解除用例绑定，然后再重新绑定它们
            cameraProvider.unbindAll()

            camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, imageAnalyzer, imageCapture)
            preview.setSurfaceProvider(previewView.surfaceProvider)
        } catch (exc: Exception) {
            exc.printStackTrace()
        }
    }

    private fun setImageAnalysis() {
        if (cameraExecutor == null || cameraExecutor?.isShutdown == true) {
            cameraExecutor = Executors.newSingleThreadExecutor()
        }

        imageAnalyzer?.setAnalyzer(cameraExecutor!!) { image ->
            imageRotationDegrees = image.imageInfo.rotationDegrees

            //println("setAnalyzer 宽 = ${image.width}, 高 = ${image.height} ,imageRotationDegrees = ${imageRotationDegrees}")

            if (bitmapBuffer == null) {
                // 图像旋转和RGB图像缓冲区仅初始化一次
                bitmapBuffer = Bitmap.createBitmap(image.width, image.height, Bitmap.Config.ARGB_8888)
            }

            detectObjects(image)
        }
    }

    private fun detectObjects(image: ImageProxy) {
        try {
            bitmapBuffer?.copyPixelsFromBuffer(image.getPlanes()[0].getBuffer());
            image.close()//关闭流，继续采集

            val matrix = Matrix()
            matrix.postRotate(image.imageInfo.rotationDegrees.toFloat())//图片分析也有个旋转角度
            val uprightImage = Bitmap.createBitmap(bitmapBuffer!!, 0, 0, bitmapBuffer!!.width, bitmapBuffer!!.height, matrix, true)
            previewBitmap = uprightImage
            //圆形图片检测
//            detectDetectionHelper.detect(uprightImage) { detectInfo ->
//                //println("总共检测到几个圆形？${detectInfo?.size}")
//                detectInfo?.getOrNull(0)?.apply {
//                    if (region?.size == 4 && detectionScore > 0.5) {
//                        //分数 = 0.81534785, 策略分数 = 0.11283743
//                        //Log.d(TAG, "分数 = ${detectionScore}, 策略分数 = ${strategyScore}")
//                        region?.let {
//                            //Log.d(TAG, "result = ${this[1]}, ${this[0]}, ${this[3]}, ${this[2]}")//左 上 右 下
//                            //这里识别的图片是完整图，需要进行比例缩放处理
//                            val previewViewWidth = realImageSize.width.toFloat()
//                            val previewViewHeight = realImageSize.height.toFloat()
//                            val width = (it[3] - it[1]) * (previewViewWidth)
//                            val height = (it[2] - it[0]) * (previewViewHeight)
//                            val topMargin = it[0] * (previewViewHeight) - (previewViewHeight - previewView.height) / 2f //减去裁剪区域(显示在屏幕外面的)
//                            val leftMargin = it[1] * (previewViewWidth) - (previewViewWidth - previewView.width) / 2f
//                            //Log.d(TAG, "width = $width, height = $height, topMargin = $topMargin, leftMargin = $leftMargin")
//
//                            //截取识别到的区域图片
//                            val newBitmap = BitmapUtils.cropBitmap(uprightImage, RectF(it[1], it[0], it[3], it[2]))
//
//                            //获取图片亮度值
//                            val luminanceValue = BitmapUtils.getBitmapAverageLuminance(newBitmap)
//
//                            //清晰度检测
////                            blurDetectionHelper.detectObjects(newBitmap) { isBlur ->
////                            }
//
//                            (context as? AppCompatActivity)?.runOnUiThread {
//                                imageAnalyzerCallback.invoke(width, height, topMargin, leftMargin, true, luminanceValue)
//                            }
//                        }
//                    } else {
//                        (context as? AppCompatActivity)?.runOnUiThread {
//                            imageAnalyzerFailCallback.invoke()
//                        }
//                    }
//                } ?: kotlin.run {
//                    (context as? AppCompatActivity)?.runOnUiThread {
//                        imageAnalyzerFailCallback.invoke()
//                    }
//                }
//            }

        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun getPreviewBitmap() = previewBitmap

    /**
     *手电筒是否可用
     */
    fun hasFlashUnit(): Boolean {
        return camera?.cameraInfo?.hasFlashUnit() == true
    }

    /**
     * @param isTorchEnable 是否打开手电筒
     */
    fun enableTorch(isTorchEnable: Boolean) {
        camera?.cameraControl?.enableTorch(isTorchEnable)
    }

    /**
     * @return 手电筒是否打开了
     */
    fun isOpenTorch(): Boolean {
        return camera?.cameraInfo?.torchState?.value == TorchState.ON
    }

    /**
     *拍照闪光灯
     */
    fun openFlashMode() {
        imageCapture?.flashMode = ImageCapture.FLASH_MODE_ON
    }

    fun closeFlashMode() {
        imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF
    }

    private fun println(string: String) {
        Log.d(TAG, string)
    }

    private fun initZoom() {
        val zoomState = camera?.cameraInfo?.zoomState
        val zoomRatio = zoomState?.value?.zoomRatio ?: 0f       //当前值
        val maxZoomRatio = zoomState?.value?.maxZoomRatio ?: 0f//缩放最大值
        val minZoomRatio = zoomState?.value?.minZoomRatio ?: 0f//缩放最小值 一般是1，比如有些支持微距镜头的是0.7
        if (maxZoomRatio >= 4f) {
            val widthRatio = realImageSize.width.toFloat() / previewView.width
            val heightRatio = realImageSize.height.toFloat() / previewView.height
            magnificationRate = magnificationRate / Math.max(widthRatio, heightRatio)
            println("缩放比例 = ${Math.max(widthRatio, heightRatio)}, magnificationRate = $magnificationRate")
            camera?.cameraControl?.setZoomRatio(magnificationRate)
        } else {
            magnificationRate = (maxZoomRatio + minZoomRatio) / 2
            camera?.cameraControl?.setZoomRatio(magnificationRate)
        }
    }

    /**
     * 放大的倍速
     */
    fun zoom(ratio: Float) {
        val zoomState = camera?.cameraInfo?.zoomState
        val zoomRatio = zoomState?.value?.zoomRatio ?: 0f        //当前值
        val maxZoomRatio = zoomState?.value?.maxZoomRatio ?: 0f//缩放最大值
        val minZoomRatio = zoomState?.value?.minZoomRatio ?: 0f//缩放最小值

        val needZoomRatio = magnificationRate * ratio //倍率计算
        val coerceValue = needZoomRatio.coerceAtLeast(minZoomRatio).coerceAtMost(maxZoomRatio)
        camera?.cameraControl?.setZoomRatio(coerceValue)
    }

    /**
     * 缩放
     */
    fun zoom(out: Boolean) {
        val zoomState = camera?.cameraInfo?.zoomState
        val zoomRatio = zoomState?.value?.zoomRatio ?: 0f        //当前值
        val maxZoomRatio = zoomState?.value?.maxZoomRatio ?: 0f//缩放最大值
        val minZoomRatio = zoomState?.value?.minZoomRatio ?: 0f//缩放最小值

        if (out) {
            //放大
            if (zoomRatio < maxZoomRatio) {
                camera?.cameraControl?.setZoomRatio((zoomRatio + zoomCoefficient))
            }
        } else {
            //缩小
            if (zoomRatio > minZoomRatio) {
                camera?.cameraControl?.setZoomRatio((zoomRatio - zoomCoefficient))
            }
        }
    }

    /**
     * 聚焦
     * @param auto 聚焦模式 是否自动
     */
    fun focus(x: Float, y: Float, auto: Boolean) {
        camera?.cameraControl?.cancelFocusAndMetering()
        val createPoint: MeteringPoint = if (auto) {
            val meteringPointFactory = DisplayOrientedMeteringPointFactory(
                    previewView.display,
                    camera?.cameraInfo!!,
                    previewView.width.toFloat(),
                    previewView.height.toFloat()
            )
            meteringPointFactory.createPoint(x, y)
        } else {
            val meteringPointFactory = previewView.meteringPointFactory
            meteringPointFactory.createPoint(x, y)
        }


        val build = FocusMeteringAction.Builder(createPoint, FocusMeteringAction.FLAG_AF)
            .setAutoCancelDuration(3, TimeUnit.SECONDS)
            .build()

        val future = camera?.cameraControl?.startFocusAndMetering(build)
//        future?.addListener({
//            try {
//                if (future.get().isFocusSuccessful) {
//                    //聚焦成功
//                    Log.e(TAG, "聚焦成功")
//                } else {
//                    //聚焦失败
//                    Log.e(TAG, "聚焦失败")
//                }
//            } catch (e: Exception) {
//                Log.e(TAG, "聚焦异常" + e.message)
//            }
//
//        }, ContextCompat.getMainExecutor(context))
    }

}


